/*
 * EditStyleDialog.java
 * 
 * Created by demory on Feb 22, 2010, 10:57:08 PM
 * 
 * Copyright 2008 David D. Emory
 * 
 * This file is part of Five Points. See <http://www.fpdev.org> for
 * additional information regarding the project.
 * 
 * Five Points is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Five Points is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Five Points.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.fpdev.apps.cart.gui;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.fpdev.apps.cart.network.LineStyle;
import org.fpdev.apps.cart.network.LineStyleInfo;
import org.fpdev.apps.cart.network.SubStyle;
import org.fpdev.util.FPUtil;
import org.fpdev.util.gui.ColorChooserDialog;
import org.fpdev.util.gui.GUIFactory;

/**
 *
 * @author demory
 */
public class EditStyleDialog extends JDialog implements ActionListener, LineStyleInfo {

  private JPanel layersListPanel_, colorSwatch_;
  private StylePreviewPanel previewPanel_;
  private JTextField nameField_, dashField_;
  private JSpinner widthSpinner_;
  private JButton newBtn_, delBtn_, upBtn_, downBtn_, changeColorBtn_, applyBtn_, okBtn_, cancelBtn_;
  private JCheckBox antialiasCB_;

  private List<LayerRow> layerRows_;
  private LayerRow selectedRow_;
  int maxRank_ = 0;

  private boolean okPressed_ = false;

  public EditStyleDialog(JFrame parent, LineStyle style) {
    super(parent, "Edit Style", true);

    layerRows_ = new LinkedList<LayerRow>();
    int rank = 0;
    for(SubStyle ss : style.getSubStyles()) {
      System.out.println("adding row");
      layerRows_.add(new LayerRow(++rank, ss.getColor(), ss.getWidth()));
    }

    layersListPanel_ = GUIFactory.newColumnPanel();
    layersListPanel_.setBorder(new EmptyBorder(3, 3, 3, 3));
    refreshLayers();
    JPanel listPanelWrapper = new JPanel(new BorderLayout());
    listPanelWrapper.add(layersListPanel_, BorderLayout.NORTH);
    JScrollPane scrollPane = new JScrollPane(listPanelWrapper);
    scrollPane.setBorder(new CompoundBorder(new EmptyBorder(2, 0, 5, 0), new BevelBorder(BevelBorder.LOWERED)));

    newBtn_ = GUIFactory.newButton("N", 30, this);
    delBtn_ = GUIFactory.newButton("D", 30, this);
    upBtn_ = GUIFactory.newButton("^", 30, this);
    downBtn_ = GUIFactory.newButton("v", 30, this);
    JPanel buttonRow = GUIFactory.newRowPanel();

    //buttonRow.add(Box.createHorizontalGlue());
    buttonRow.add(newBtn_);
    buttonRow.add(delBtn_);
    buttonRow.add(upBtn_);
    buttonRow.add(downBtn_);
    buttonRow.add(Box.createHorizontalGlue());

    previewPanel_ = new StylePreviewPanel(this, 1, 24, Color.BLACK, 2, false);

    JPanel layerSelPanel = new JPanel(new BorderLayout());
    layerSelPanel.add(scrollPane, BorderLayout.CENTER);
    layerSelPanel.add(buttonRow, BorderLayout.NORTH);
    //layerSelPanel.add(previewPanel_, BorderLayout.SOUTH);
    layerSelPanel.setBorder(new EmptyBorder(0, 0, 0, 10));

    // LAYER OPTIONS PANEL

    JPanel colorRow = GUIFactory.newRowPanel();
    colorRow.setAlignmentX(LEFT_ALIGNMENT);
    colorRow.add(GUIFactory.newLabel("Color: "));
    colorSwatch_ = new JPanel();
    colorSwatch_.setPreferredSize(new Dimension(18,18));
    colorSwatch_.setMaximumSize(new Dimension(18,18));
    colorSwatch_.setBorder(new BevelBorder(BevelBorder.LOWERED));
    colorRow.add(colorSwatch_);
    colorRow.add(Box.createHorizontalStrut(5));
    changeColorBtn_ = GUIFactory.newButton("Change..", 60, this);
    colorRow.add(changeColorBtn_);
    colorRow.add(Box.createHorizontalGlue());

    JPanel widthRow = GUIFactory.newRowPanel();
    widthRow.setAlignmentX(LEFT_ALIGNMENT);
    widthRow.add(GUIFactory.newLabel("Width: "));
    widthSpinner_ = new JSpinner();
    widthSpinner_.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        applyLayerEdits();
      }
    });
    widthRow.add(widthSpinner_);
    widthRow.add(Box.createHorizontalGlue());

    JPanel dashRow = GUIFactory.newRowPanel();
    dashRow.setAlignmentX(LEFT_ALIGNMENT);
    dashField_ = GUIFactory.newTextField("", 50, 0);
    applyBtn_ = GUIFactory.newButton("Apply", 40, this);
    dashRow.add(GUIFactory.newLabel("Dashing: "));
    dashRow.add(dashField_);
    dashRow.add(Box.createHorizontalStrut(5));
    dashRow.add(applyBtn_);


    JPanel layerPropsSubPanel = GUIFactory.newColumnPanel();
    layerPropsSubPanel.add(colorRow);
    layerPropsSubPanel.add(Box.createVerticalStrut(5));
    layerPropsSubPanel.add(widthRow);
    layerPropsSubPanel.add(Box.createVerticalStrut(5));
    layerPropsSubPanel.add(dashRow);
    layerPropsSubPanel.setBorder(new EmptyBorder(0, 5, 0, 5));
    //layerPropsSubPanel.add(Box.createVerticalGlue());

    /*JPanel layerPropsBtnRow = GUIFactory.newRowPanel();
    layerPropsBtnRow.add(Box.createHorizontalGlue());
    layerPropsBtnRow.add(applyBtn_);
    layerPropsBtnRow.add(Box.createHorizontalGlue());*/

    JPanel layerPropsPanel = new JPanel(new BorderLayout());
    layerPropsPanel.setBorder(new TitledBorder("Layer Properties"));
    layerPropsPanel.add(layerPropsSubPanel, BorderLayout.NORTH);
    //layerPropsPanel.add(layerPropsBtnRow, BorderLayout.SOUTH);

    JPanel previewRow = new JPanel(new BorderLayout());
    previewRow.add(new JLabel("Preview: "), BorderLayout.WEST);
    previewRow.add(previewPanel_, BorderLayout.CENTER);
    antialiasCB_ = GUIFactory.newCheckBox("Show antialiased", false);
    antialiasCB_.addActionListener(this);
    previewRow.add(antialiasCB_, BorderLayout.EAST);

    JPanel bottomRow = GUIFactory.newRowPanel();
    nameField_ = GUIFactory.newTextField(style.getStyleName(), 50, 0);
    okBtn_ = GUIFactory.newButton("OK", 60, this);
    cancelBtn_ = GUIFactory.newButton("Cancel", 60, this);
    bottomRow.add(new JLabel("Name: "));
    bottomRow.add(nameField_);
    bottomRow.add(Box.createHorizontalStrut(25));
    bottomRow.add(okBtn_);
    bottomRow.add(Box.createHorizontalStrut(5));
    bottomRow.add(cancelBtn_);
    //bottomRow.setBorder(new EmptyBorder(8, 0, 0, 0));

    // TOP-LEVEL LAYOUT
    JPanel topPanel = new JPanel(new BorderLayout()); //new GridLayout(1, 2));
    topPanel.add(layerSelPanel, BorderLayout.WEST);
    topPanel.add(layerPropsPanel, BorderLayout.CENTER);

    JPanel bottomPanel = GUIFactory.newColumnPanel();
    bottomPanel.add(Box.createVerticalStrut(6));
    bottomPanel.add(previewRow);
    bottomPanel.add(Box.createVerticalStrut(6));
    bottomPanel.add(bottomRow);

    JPanel mainPanel = new JPanel(new BorderLayout());
    mainPanel.add(topPanel, BorderLayout.CENTER);
    mainPanel.add(bottomPanel, BorderLayout.SOUTH);
    mainPanel.setBorder(new EmptyBorder(5, 5, 5, 5));

    getContentPane().add(mainPanel);
    setSize(360, 240);
    setLocationRelativeTo(parent);
    setPropertiesEnabled(false);
    setVisible(true);

  }

  public void actionPerformed(ActionEvent e) {
    if(e.getSource() == newBtn_) newLayer();
    if(e.getSource() == delBtn_) deleteLayer(selectedRow_);
    if(e.getSource() == upBtn_) bringForward(selectedRow_);
    if(e.getSource() == downBtn_) sendBackward(selectedRow_);

    if(e.getSource() == changeColorBtn_) {
      ColorChooserDialog chooserDialog = new ColorChooserDialog(this, colorSwatch_.getBackground());
      colorSwatch_.setBackground(chooserDialog.getColor());
      applyLayerEdits();
    }
    if(e.getSource() == applyBtn_) {
      try {
        selectedRow_.dash_ = SubStyle.parseDash(dashField_.getText());
        applyLayerEdits();
      } catch(NumberFormatException ex) {
        JOptionPane.showMessageDialog(this, "Invalid dash input; must be comma-separated list of numbers");
      }
    }

    if(e.getSource() == antialiasCB_) {
      previewPanel_.setAntialias(antialiasCB_.isSelected());
      previewPanel_.repaint();
    }
    
    if(e.getSource() == okBtn_) {
      okPressed_ = true;
      setVisible(false);
    }
    if(e.getSource() == cancelBtn_) {
      setVisible(false);
    }
  }
  
  public boolean okPressed() {
    return okPressed_;
  }

  public String getStyleName() {
    return nameField_.getText();
  }

  public List<SubStyle> getSubStyles() {
    List<SubStyle> list = new LinkedList<SubStyle>();
    for(LayerRow row : layerRows_)
      list.add(new SubStyle(row.width_, row.color_, row.dash_));
    return list;
  }

  private void setPropertiesEnabled(boolean enabled) {
    if(enabled == false) {
      colorSwatch_.setBackground(this.getBackground());
      dashField_.setText("");
    }
    changeColorBtn_.setEnabled(enabled);
    widthSpinner_.setEnabled(enabled);
    dashField_.setEnabled(enabled);
    applyBtn_.setEnabled(enabled);
  }

  private void applyLayerEdits() {
    selectedRow_.color_ = colorSwatch_.getBackground();
    if(FPUtil.isInteger(widthSpinner_.getValue().toString())) {
      selectedRow_.width_ = Integer.parseInt(widthSpinner_.getValue().toString());
    }
    refreshLayers();
    previewPanel_.repaint();
  }

  private void newLayer() {

    for(LayerRow row : layerRows_) row.rank_++;
    layerRows_.add(new LayerRow(1, Color.BLACK, 2));
    System.out.println("new layer");
    refreshLayers();
    previewPanel_.repaint();
  }


  private void deleteLayer(LayerRow row) {
    if(row == null) return;
    layerRows_.remove(row);
    if(row == selectedRow_) selectedRow_ = null;
    refreshLayers();
    setPropertiesEnabled(false);
    previewPanel_.repaint();
  }

  private void bringForward(LayerRow row) {
    if(row == null) return;
    int index = layerRows_.indexOf(row);
    if(index <= 0) return;
    row.rank_--;
    layerRows_.get(index-1).rank_++;
    refreshLayers();
    previewPanel_.repaint();
  }

  private void sendBackward(LayerRow row) {
    if(row == null) return;
    int index = layerRows_.indexOf(row);
    if(index >= layerRows_.size()-1) return;
    row.rank_++;
    layerRows_.get(index+1).rank_--;
    refreshLayers();
    previewPanel_.repaint();
  }

  private void refreshLayers() {
    Collections.sort(layerRows_);
    layersListPanel_.removeAll();
    //layersListPanel_.revalidate();
    for(LayerRow row : layerRows_) {
      layersListPanel_.add(row);
      layersListPanel_.add(Box.createVerticalStrut(3));
      /*if(row == selectedRow_)
        row.setBorder(new LineBorder(Color.red, 2));
      else
        row.setBorder(new LineBorder(Color.gray, 1));*/
      row.repaint();//revalidate();
    }
    layersListPanel_.revalidate();
  }

  private void rowSelected(LayerRow row) {
    selectedRow_ = row;
    colorSwatch_.setBackground(row.color_);
    widthSpinner_.setValue(row.width_);
    setPropertiesEnabled(true);
    refreshLayers();
  }

  private class LayerRow extends JPanel implements Comparable<LayerRow> {

    private int rank_, width_;
    private Color color_;
    private float[] dash_;

    public LayerRow(int rank, Color color, int width) {
      setPreferredSize(new Dimension(1, 24));
      rank_ = rank;
      color_ = color;
      width_ = width;

      addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
          rowSelected(LayerRow.this);
        }
      });
    }

    @Override
    public void paintComponent(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;

      g2d.setColor(this == selectedRow_ ? Color.red : Color.BLACK);
      g2d.fillRect(0, 0, getWidth(), getHeight());
      g2d.setColor(EditStyleDialog.this.getBackground());
      int bWidth = this == selectedRow_ ? 2 : 1;
      g2d.fillRect(bWidth, bWidth, getWidth()-bWidth*2, getHeight()-bWidth*2);


      int y = getHeight()/2;
      g2d.setStroke(new BasicStroke(width_, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1, dash_, 0));
      g2d.setColor(color_);

      g2d.drawLine(5, y, getWidth()-5, y);
    }

    public int compareTo(LayerRow o) {
      return new Integer(rank_).compareTo(new Integer(o.rank_));
    }

  }

}
